﻿///<reference path="../typings/jquery/jquery.d.ts"/>
///<reference path="../typings/linq/linq.3.0.3-Beta4.d.ts"/>
///<reference path="../typings/knockout/knockout.d.ts"/>
///<reference path="../collections.ts"/>

module Enferno.Public.Web.Products {

    export class Product {

        public id: string;
        public description: string;
        public descriptionHeader: string;
        public flags: Array<number>;
        public name: string;
        public unitOfMeasurement: string;
        public _onHandStatusText1: string;
        public _onHandStatusText2: string;
        public _onHandStatusCount: number;
        public getOnHandStatusDisplayText: (text1: string, text2: string, count: number) => string;
        public priceFormator: (price: number) => string;

        public recommendedQuantity: number;
        private _displayPrice: number;
        private _catalogPrice: number;
        public vatRate: number;
        public _priceListId: number;

        public files: Array<FileInfo>;
        public defaultImage: KnockoutObservable<FileInfo>;
        public additionalImages: KnockoutObservableArray<FileInfo>;

        public variants: Array<ProductVariant>;
        private variantParametrics: Array<Parametric>;

        private variantParametricsRenderedSpecifically: collections.Set<number>;

        public displayPrice: KnockoutObservable<number>;
        public catalogPrice: KnockoutObservable<number>;
        public partNo: KnockoutObservable<string>;
        public priceListId: KnockoutObservable<number>;
        public onHandStatusDisplayText: KnockoutObservable<string>;
        public haveActiveVariant: KnockoutObservable<boolean>;

        public static onInitializedFunctions = new Array<(initializedProduct: Product) => void>();

        public variantParametricIdsToSelectedValues: collections.Dictionary<number, KnockoutObservable<any>>;
        private variantParametricIdsToPossibleValues: collections.Dictionary<number, Array<ParametricValue>>;
        private variantParametricIdsToSelectionChangedHandlers: collections.Dictionary<number, () => {}>;
        private variantParametricIdsToSelectionOptions: collections.Dictionary<number, ParametricSelectionOptions>;
        private defaultParametricSelectionOptions: ParametricSelectionOptions;

        public static domNodeBindingSelector = ".product-component";
        public static activeProduct: Product;

        private activeVariant: ProductVariant;

        public static init(data: any, parametricIdsRenderedExplicitly: Array<number>): void {
            var domNodes = $(Product.domNodeBindingSelector);
            var product = new Product(data);
            Product.activeProduct = product;
            Enumerable.from(parametricIdsRenderedExplicitly).forEach(parametricId => product.registerParametricAsRenderedExplicitly(parametricId));

            Enumerable.from(Product.onInitializedFunctions).forEach(fn => fn(product));

            if (product.variants.length == 1) {
                product.updateToVariant(product.variants[0]);
            }

            Enumerable.from(domNodes).forEach(domNode => ko.applyBindings(product, domNode));
        }

        constructor(serverData?: any) {
            this.variantParametricIdsToPossibleValues = new collections.Dictionary<number, Array<ParametricValue>>();
            this.variantParametricIdsToSelectionChangedHandlers = new collections.Dictionary<number, () => {}>();
            this.variantParametricIdsToSelectedValues = new collections.Dictionary<number, KnockoutObservable<any>>();
            this.variantParametricIdsToSelectionOptions = new collections.Dictionary<number, ParametricSelectionOptions>();
            this.variantParametricsRenderedSpecifically = new collections.Set<number>();

            this.activeVariant = null;

            this.haveActiveVariant = ko.observable(false);
            this.priceListId = ko.observable(null);
            this.partNo = ko.observable(null);
            this.onHandStatusDisplayText = ko.observable(null);

            this.variants = new Array<ProductVariant>();
            this.variantParametrics = new Array<Parametric>();
            this.files = new Array<FileInfo>();

            if (serverData != null) {
                this.setDataFromServerProduct(serverData);
            }
        }

        public registerParametricSelectionChangedHandler(parametricId: number, handler: () => {}): void {
            this.variantParametricIdsToSelectionChangedHandlers.setValue(parametricId, handler);
        }

        private registerParametricAsRenderedExplicitly(parametricId: number) {
            this.variantParametricsRenderedSpecifically.add(parametricId);
        }

        public getVariantParametricsToRender(): Array<Parametric> {
            var genericParametrics = Enumerable.from(this.variantParametrics)
                .where(parametric => {
                    return !this.variantParametricsRenderedSpecifically.contains(parametric.id);
                })
                .toArray();

            if (this.hasVariantsButNoVariantParametrics())
                genericParametrics = this.getDefaultVariantParametrics();

            return genericParametrics;
        }

        public registerDefaultParametricsSelectionOptions(domNodesSelector: () => Array<Element>,
            onIsSelectable: (domNode: Element) => {}, onIsNotSelectable: (domNode: Element) => {}, onSetSelected: (domElement: Element, selected: boolean) => {},
            valueExtractor?: (domNode: Element) => string,
            idExtractor?: (domNode: Element) => number) {
            var options = new ParametricSelectionOptions();
            options.domNodesSelector = domNodesSelector;
            options.onIsSelectable = onIsSelectable;
            options.onIsNotSelectable = onIsNotSelectable;
            options.valueExtractor = valueExtractor;
            options.idExtractor = idExtractor;
            options.onSetSelected = onSetSelected;

            this.defaultParametricSelectionOptions = options;

        }

        public registerParametricSelectionOptions(parametricId: number, domNodesSelector: () => Array<Element>,
            onIsSelectable: (domNode: Element) => {}, onIsNotSelectable: (domNode: Element) => {}, onSetSelected: (domElement: Element, selected: boolean) => {},
            valueExtractor?: (domNode: Element) => string,
            idExtractor?: (domNode: Element) => number) {

            var parametricSelectionOptions = new ParametricSelectionOptions();
            parametricSelectionOptions.domNodesSelector = domNodesSelector;
            parametricSelectionOptions.onIsSelectable = onIsSelectable;
            parametricSelectionOptions.onIsNotSelectable = onIsNotSelectable;
            parametricSelectionOptions.valueExtractor = valueExtractor;
            parametricSelectionOptions.idExtractor = idExtractor;
            parametricSelectionOptions.onSetSelected = onSetSelected;

            this.variantParametricIdsToSelectionOptions.setValue(parametricId, parametricSelectionOptions);
        }

        public getValuesForVariantParametric(parametricId: number): Array<ParametricValue> {
            var values = this.variantParametricIdsToPossibleValues.getValue(parametricId);

            if (this.hasVariantsButNoVariantParametrics()) {
                //setup default variant parametrics
                var defaultVaraintParametrics = this.getDefaultVariantParametrics();
                var matchingParametric = Enumerable.from(defaultVaraintParametrics).single(parametric => parametric.id == parametricId);

                values = matchingParametric.values;
            }
            return values;
        }

        public getSelectedValueHolderForVaraiantParametric(parametricId: number): KnockoutObservable<any> {
            var value = this.variantParametricIdsToSelectedValues.getValue(parametricId);
            return value;
        }

        public setSelectedValueForParametric(parametricId: number, parametricValue: ParametricValue): void {
            var valueParametric = this.variantParametricIdsToSelectedValues.getValue(parametricId);

            if (valueParametric == null) {
                valueParametric = ko.observable<ParametricValue>();
            }

            valueParametric(parametricValue);
        }

        public getPriceFormattedString(price: number): string {
            if (this.priceFormator != null)
                return this.priceFormator(price);
            return price.toString();
        }

        private getDefaultVariantParametrics(variantId?: number): Array<Parametric> {
            var defaultVariantParametric = new Parametric();
            //TODO: these are hardcoded now. Should be parameters.
            defaultVariantParametric.id = -1;
            defaultVariantParametric.name = "Variant";

            var variantsToGenerateParametricsFrom = this.variants;

            if (variantId != null) {
                variantsToGenerateParametricsFrom = Enumerable.from(this.variants).where(variant => variant.id == variantId).toArray();
            }

            var values = Enumerable.from(variantsToGenerateParametricsFrom)
                .select(variant => {
                    var value = new ParametricValue({ value: variant.name, id: 0, sortOrder: 0 });
                    return value;
                }).toArray();

            defaultVariantParametric.values = values;
            return new Array<Parametric>(defaultVariantParametric);
        }

        private hasVariantsButNoVariantParametrics(): boolean {
            return this.variants.length > 1 && this.variantParametrics.length == 0;
        }

        private setDataFromServerProduct(serverData: any): void {
            this.id = serverData.id;
            this.description = serverData.description;
            this.descriptionHeader = serverData.descriptionHeader;
            this.flags = serverData.flags;
            this.name = serverData.name;
            this.unitOfMeasurement = serverData.unitOfMeasurement;
            this._onHandStatusText1 = serverData.onHandStatusText1;
            this._onHandStatusText2 = serverData.onHandStatusText2;
            this._onHandStatusCount = serverData.onHandStatusCount;
            this.recommendedQuantity = serverData.recommendedQuantity;
            this._displayPrice = serverData.displayPrice;
            this.displayPrice = ko.observable(serverData.displayPrice);
            this._catalogPrice = serverData.catalogPrice;
            this.catalogPrice = ko.observable(serverData.catalogPrice);
            this.vatRate = serverData.vatRate;
            this._priceListId = serverData.priceListId;

            Enumerable.from(serverData.variants).forEach(variant => {
                this.variants.push(new ProductVariant(variant));
            });

            Enumerable.from(serverData.variantParametrics).forEach(variantParametric => {
                this.variantParametrics.push(new Parametric(variantParametric));
            })

            //set up variantParametric map and variant parametric properties
            this.variantParametricIdsToSelectedValues = new collections.Dictionary<number, KnockoutObservable<any>>();

            var variantParametrics = serverData.variantParametrics;
            if (this.hasVariantsButNoVariantParametrics()) {
                variantParametrics = this.getDefaultVariantParametrics();
            }

            Enumerable.from(variantParametrics).forEach(variantParametric => {
                var selectedParametricValue = ko.observable<any>(null);

                selectedParametricValue.subscribe((newParametricValue) => {

                    if (typeof newParametricValue === "string") {
                        newParametricValue = this.getVariantParametricValueWithValue(variantParametric.id, newParametricValue.toString());
                    }

                    if (newParametricValue != null) {
                        this.setVariantParametricValue(variantParametric.id, newParametricValue);
                    } else {
                        //new parametric value is null, reset selected variant.
                        this.resetSelectedVariant();
                    }

                });

                this.variantParametricIdsToSelectedValues.setValue(variantParametric.id, selectedParametricValue);
                var variantValues = new Array<ParametricValue>();
                Enumerable.from(variantParametric.values).forEach(variantParametricServerData => variantValues.push(new ParametricValue(variantParametricServerData)));

                this.variantParametricIdsToPossibleValues.setValue(variantParametric.id, variantValues);
            });

            this.files = new Array<FileInfo>();
            Enumerable.from(serverData.files).forEach(fileInfo => {
                this.files.push(new FileInfo(fileInfo));
            });

            this.defaultImage = ko.observable<FileInfo>(this.getDefaultImage());
            this.additionalImages = ko.observableArray<FileInfo>(this.getAdditionalImages());
        }

        private setVariantParametricValue(parametricId: number, parametricValue: ParametricValue): void {

            //check all variants and find the first one with a matching variant parametric value
            var variantsWithValue = this.getVariantsWithValue(parametricId, parametricValue);

            Enumerable.from(this.variantParametricIdsToSelectedValues.keys()).forEach(key => {
                var koValue = this.variantParametricIdsToSelectedValues.getValue(key);
            });

            if (variantsWithValue.length > 0) {
                //find the variant that matches all of the set variant parametrics
                var matchingVariant = Enumerable.from(variantsWithValue).first(variant => {
                    var isMatch = true;
                    Enumerable.from(this.variantParametricIdsToSelectedValues.keys()).forEach(key => {
                        var koValue = this.variantParametricIdsToSelectedValues.getValue(key);
                        if (koValue() != null) {

                            var value: ParametricValue = null;

                            if (typeof koValue() === "string") {
                                //assume we have a value. Find the parametric value with the correspronding value.
                                //Note! We have to do this since when we create default variant parametrics we get a string here and not a ParametricValue object. Can't understand why...
                                var val = <string>koValue();
                                value = this.getVariantParametricValueWithValue(key, val);
                            } else { //assume that the value is of type ParametricValue already.
                                value = koValue();
                            }

                            var variantParametric = Enumerable.from(variant.variantParametrics).single(parametric => parametric.id == key);
                            var variantValue = variantParametric.values[0]; //also, here we should support multiple values
                            if (!value.equals(variantValue)) {
                                isMatch = false;
                                return;
                            }
                        }
                    })

                    return isMatch;
                });

                if (this.activeVariant == null || matchingVariant.id != this.activeVariant.id) {
                    this.activeVariant = matchingVariant;
                    this.updateToVariant(matchingVariant, parametricId, parametricValue);
                }
            }

        }

        private getVariantParametricValueWithValue(parametricId: number, value: string): ParametricValue {
            var possibleValues = this.variantParametricIdsToPossibleValues.getValue(parametricId);
            return Enumerable.from(possibleValues).single(parametricValue => parametricValue.value == value);
        }

        private getVariantsWithValue(parametricId: number, parametricValue: ParametricValue) {

            var variants = this.variants;
            if (this.hasVariantsButNoVariantParametrics()) {
                //create default variant parametrics.
                Enumerable.from(variants).forEach(variant => {
                    var defaultVariantParametrics = this.getDefaultVariantParametrics(variant.id);
                    variant.variantParametrics = defaultVariantParametrics;
                });
            }

            var variantsWithValue = Enumerable.from(variants).where(variant => {

                var parametricForId = Enumerable.from(variant.variantParametrics).single(parametric => parametric.id == parametricId);

                //todo, we should support parametrics with multiple values
                if (parametricValue.id != null && parametricValue.id != 0 && parametricForId.values.length == 1 && parametricForId.values[0].id == parametricValue.id) { //if we got the value id, compare with that.
                    return true;
                } else if (parametricValue.value != null && parametricForId.values.length == 1 && parametricForId.values[0].value == parametricValue.value) { //else, if we got the value, compare with that
                    return true;
                }

                return false;
            }).toArray();

            //if no variants where found, return all
            if (variantsWithValue.length == 0)
                return this.variants;

            return variantsWithValue;
        }

        private resetSelectedVariant(): void {
            //reset selected values
            Enumerable.from(this.variantParametricIdsToSelectedValues.keys())
                .forEach(variantParametricKey => {
                    var selectedValue = this.variantParametricIdsToSelectedValues.getValue(variantParametricKey);
                    selectedValue(null);
                });

            Enumerable.from(this.variantParametricIdsToPossibleValues.keys())
                .forEach(variantParametricKey => {
                    var values = this.variantParametricIdsToPossibleValues.getValue(variantParametricKey);
                    Enumerable.from(values).forEach((parametricValue: ParametricValue) => parametricValue.isSelectable(true));
                    this.onParametricChanged(variantParametricKey);
                });

            this.updatePrice();
            this.updateImages();

            this.partNo(null);
            this.priceListId(null);
            this.onHandStatusDisplayText(null);

            this.haveActiveVariant(false);

            this.activeVariant = null;
        }

        private updateToVariant(variant: ProductVariant, parametricId?: number, parametricValue?: ParametricValue) {
            this.updatePrice(variant);
            this.updateImages(variant);
            this.updateOnHandDisplayText(variant);

            this.partNo(variant.partNo);
            this.priceListId(variant.priceListId);

            this.haveActiveVariant(true);

            if (parametricId != null) {
                this.updateParametricSelection(parametricId, parametricValue);
            }
        }

        private updatePrice(variant?: ProductVariant): void {
            if (variant != null) {
                this.displayPrice(variant.displayPrice);
                this.catalogPrice(variant.catalogPrice);
            } else {
                this.displayPrice(this._displayPrice);
                this.catalogPrice(this._catalogPrice);
            }
        }

        private updateImages(variant?: ProductVariant): void {
            this.defaultImage(this.getDefaultImage());
            this.additionalImages = ko.observableArray<FileInfo>(this.getAdditionalImages())
        }

        private updateOnHandDisplayText(variant?: ProductVariant): void {
            if (variant != null) {
                if (this.getOnHandStatusDisplayText != null)
                    this.onHandStatusDisplayText(this.getOnHandStatusDisplayText(variant.onHandStatusText1, variant.onHandStatusText2, variant.onHandStatusCount));
                else
                    this.onHandStatusDisplayText(variant.onHandStatusText1);
            } else {
                this.onHandStatusDisplayText(null);
            }
        }

        private getDefaultImage(): FileInfo {

            var defaultImage: FileInfo = null;
            if (this.activeVariant != null) {
                defaultImage = Enumerable.from(this.activeVariant.files).singleOrDefault(file => file.type == FileType.VariantImage && file.url != null);
            }

            if (defaultImage == null)
                defaultImage = Enumerable.from(this.files).single(file => file.type == FileType.DefaultImage);

            return defaultImage;
        }

        private getAdditionalImages(): Array<FileInfo> {
            var additionalImages: Array<FileInfo> = null;
            if (this.activeVariant != null) {
                var foundImages = Enumerable.from(this.files).where(file => file.type == FileType.AdditionalImage).toArray();
                if (foundImages.length > 0)
                    additionalImages = foundImages;
            }

            if (additionalImages == null) {
                additionalImages = Enumerable.from(this.files).where(file => file.type == FileType.AdditionalImage).toArray();
            }

            return additionalImages;
        }

        private updateParametricSelection(parametricId: number, parametricValue: ParametricValue) {
            var variantsWithValue = this.getVariantsWithValue(parametricId, parametricValue);

            var variantParametricIdsToSelectableValues = new collections.Dictionary<number, Array<ParametricValue>>();

            //find all values for the variants that had the given value and record them for later.
            Enumerable.from(variantsWithValue).forEach(variant => {
                Enumerable.from(variant.variantParametrics).forEach(variantParametric => {
                    var valueList = variantParametricIdsToSelectableValues.getValue(variantParametric.id);
                    if (valueList == null) {
                        valueList = new Array<ParametricValue>();
                    }
                    //TODO: support multiple parametric values
                    var valueToAdd = variantParametric.values[0]
                    var containsValue = Enumerable.from(valueList).any(val => val.equals(valueToAdd));
                    if (!containsValue) {
                        valueList.push(valueToAdd);
                        variantParametricIdsToSelectableValues.setValue(variantParametric.id, valueList);
                    }
                })
            });

            Enumerable.from(this.variantParametricIdsToPossibleValues.keys()).forEach(possibleVariantParametricKey => {
                var possibleVariantParametricValues = this.variantParametricIdsToPossibleValues.getValue(possibleVariantParametricKey);

                var activeVariantParametric = Enumerable.from(this.activeVariant.variantParametrics)
                    .single(variantParametric => variantParametric.id == possibleVariantParametricKey);

                var valueThatShouldBeSelected = activeVariantParametric.values[0];

                if (possibleVariantParametricKey != parametricId) { //only disable values for the parameters not choosen.
                    var selectableValues = variantParametricIdsToSelectableValues.getValue(possibleVariantParametricKey);

                    Enumerable.from(possibleVariantParametricValues).forEach((possibleValue: ParametricValue) => {
                        if (!Enumerable.from(selectableValues).any(selectableValue => selectableValue.equals(possibleValue))) {
                            possibleValue.isSelectable(false);
                        } else {
                            possibleValue.isSelectable(true);
                        }
                    });
                }
                //} else { //for the parametric that was selected from, set all values to selectable
                //    Enumerable.from(possibleVariantParametricValues).forEach((possibleValue: ParametricValue) => possibleValue.isSelectable(true));
                //}

                this.onParametricChanged(possibleVariantParametricKey, valueThatShouldBeSelected);
            });


        }

        private onParametricChanged(parametricId: number, valueThatShouldBeSelected?: ParametricValue): void {

            //call changedHandler if any
            var changedHandler = this.variantParametricIdsToSelectionChangedHandlers.getValue(parametricId);
            if (changedHandler != null) {
                changedHandler();
            }

            var parametricSelectionOptions = this.variantParametricIdsToSelectionOptions.getValue(parametricId);

            if (parametricSelectionOptions == null) {
                if (this.defaultParametricSelectionOptions != null)
                    parametricSelectionOptions = this.defaultParametricSelectionOptions;
                else
                    return;
            }

            var domElements = parametricSelectionOptions.domNodesSelector(parametricId);
            var parametricValues = this.getValuesForVariantParametric(parametricId);

            Enumerable.from(domElements).forEach((domElement: Element) => {
                var parametricValue: ParametricValue = null;

                if (parametricSelectionOptions.valueExtractor != null) {
                    var value = parametricSelectionOptions.valueExtractor(domElement);
                    parametricValue = Enumerable.from(parametricValues).single(function (val) { return val.value == value; });
                } else if (parametricSelectionOptions.idExtractor != null) {
                    var id = parametricSelectionOptions.idExtractor(domElement);
                    parametricValue = Enumerable.from(parametricValues).single(function (val) { return val.id == id; });
                } else {
                    throw "Neither valueExtractor nor idExtractor is available. One of them must be specified!";
                }

                if (!parametricValue.isSelectable()) {
                    parametricSelectionOptions.onIsNotSelectable(domElement)
                } else {
                    parametricSelectionOptions.onIsSelectable(domElement);
                }

                var selected = valueThatShouldBeSelected != null && valueThatShouldBeSelected.equals(parametricValue);
                parametricSelectionOptions.onSetSelected(domElement, selected);
            });
        }
    }

    class ParametricSelectionOptions {
        public domNodesSelector: (parametricId: number) => Array<Element>;
        public valueExtractor: (domNode: Element) => string;
        public idExtractor: (domNode: Element) => number;
        public onIsSelectable: (domNode: Element) => {};
        public onIsNotSelectable: (domNode: Element) => {};
        public onSetSelected: (domNode: Element, selected: boolean) => {};
    }

    export class ProductVariant {

        public id: number;
        public name: string;
        public displayPrice: number;
        public catalogPrice: number;
        public partNo: string;
        public priceListId: number;
        public onHandStatusText1: string;
        public onHandStatusText2: string;
        public onHandStatusCount: number;
        public files: Array<FileInfo>;
        public variantParametrics: Array<Parametric>;


        constructor(serverData?: any) {
            this.variantParametrics = new Array<Parametric>();
            this.files = new Array<FileInfo>();

            if (serverData != null) {
                this.id = serverData.id;
                this.name = serverData.name;
                this.displayPrice = serverData.displayPrice;
                this.catalogPrice = serverData.catalogPrice;
                this.partNo = serverData.partNo;
                this.priceListId = serverData.priceListId;
                this.onHandStatusText1 = serverData.onHandStatusText1;
                this.onHandStatusText2 = serverData.onHandStatusText2;
                this.onHandStatusCount = serverData.onHandStatusCount;

                if (serverData.files != null) {
                    Enumerable.from(serverData.files).forEach(file => this.files.push(new FileInfo(file)));
                }

                Enumerable.from(serverData.variantParametrics).forEach(parametric => this.variantParametrics.push(new Parametric(parametric)));
            }
        }

    }

    export class FileInfo {

        public url: string;
        public type: FileType;
        public altText: string;

        constructor(serverObject?: any) {
            if (serverObject != null) {
                this.url = serverObject.url;
                this.type = serverObject.type;
                this.altText = serverObject.altText;
            }
        }

    }

    export class Parametric {

        constructor(serverObject?: any) {
            this.values = new Array<ParametricValue>();

            if (serverObject != null) {
                this.id = serverObject.id;
                this.name = serverObject.name;
                this.description = serverObject.description;
                this.unitOfMeasurement = serverObject.unitOfMeasurement;
                this.isPrimary = serverObject.isPrimary;
                this.groupId = serverObject.groupId;
                this.group = serverObject.group;

                Enumerable.from(serverObject.values).forEach(value => this.values.push(new ParametricValue(value)));
            }
        }

        public toString(): string {
            return this.id.toString();
        }

        public id: number;
        public name: string;
        public description: string;
        public unitOfMeasurement: string;
        public isPrimary: boolean;
        public groupId: number;
        public group: string;
        public values: Array<ParametricValue>;

    }

    export class ParametricValue {

        constructor(serverObject?: any) {
            this.isSelectable = ko.observable<boolean>(true);

            if (serverObject != null) {
                this.id = serverObject.id;
                this.name = serverObject.name;
                this.description = serverObject.description;
                this.imageUrl = serverObject.imageUrl;
                this.code = serverObject.code;
                this.value = serverObject.value;
                this.sortOrder = serverObject.sortOrder;
            }
        }

        public toString(): string {
            if (this.id != null)
                return this.id.toString();
            return this.value;
        }

        public equals(otherValue: ParametricValue): boolean {
            if (this.id != null && this.id != 0) {
                return this.id == otherValue.id;
            } else {
                return this.value == otherValue.value;
            }
        }

        public id: number;
        public name: string;
        public description: string;
        public imageUrl: string;
        public code: string;
        public value: string;
        public sortOrder: number;
        public isSelectable: KnockoutObservable<boolean>;
    }

    export enum FileType {
        DefaultImage = 1,
        VariantImage = 2,
        Document = 6,
        EmbeddedVideo = 10,
        AdditionalImage = 11,
        ProductManual = 13,
        ExternalImage = 14,
        EnvironmentalImage = 15,
        InternalImage = 17,
        IllustrationOrSymbol = 18,
        Logotype = 19,
        DetailImage = 20,
        AlternateImage = 21,
        Text = 22,
        ModelInformationSalesText = 23,
        AssemblyInstruction = 24,
        FactSheet = 25,
        Broschure = 26,
        ExternalTrademark = 27,
        CareInstructions = 28,
        Symbols = 29,
        QualityDocument = 30,
        Illustration = 31,
        PackningInstruction = 32,
        DrawingUnderlay = 33,
        TestProtocol = 34,
        CutThrughImage = 35,
        PriceSheet = 36,
        DiscountFactSheet = 37,
        ProductCloseUp = 38,
        MultiProductImage = 39,
        InstallationImage = 40,
        MultiProductImageSerie = 41,
        MaterialSample = 42,
    }

} 